﻿using Anley.DomainDrivenDesign.Contract.Domain;
using Anley.DomainDrivenDesign.Contract.DomainAdapter;
using Anley.DomainDrivenDesign.Contract.Extension;
using Anley.DomainDrivenDesign.Contract.Helper;

namespace Anley.DomainDrivenDesign.Contract.Infrastructure;

/// <summary>
/// 仓储抽象类
/// </summary>
public abstract class DbRepository
    : IDbRepository
{
    /// <summary>
    /// 构造函数
    /// </summary>
    protected DbRepository()
    {
        DbContextProvider = ServiceProviderHelper.ServiceProvider
            .GetRequiredService<IDbRepositoryContextProvider>();
    }

    // 仓储上下文提供程序
    public IDbRepositoryContextProvider DbContextProvider { get; private set; }

    // 仓储上下文
    public IDbRepositoryContext DbContext => DbContextProvider.GetRepositoryContext();
}

/// <summary>
/// 仓储类
/// </summary>
public abstract class Repository<TEntity, TKey>
    : DbRepository, IRepository<TEntity, TKey>
    where TEntity : class, IEntity<TKey>
    where TKey : struct
{
    /// <summary>
    /// 表名称
    /// </summary>
    protected string TableName => typeof(TEntity).GetTableName();

    // 添加
    public async Task<int> InsertAsync(TEntity entity, IDbTransaction? transaction = null)
    {
        return await DbContext.Connection.InsertAsync(entity, transaction);
    }

    // 获取列表
    public async Task<IList<TEntity>> ListAsync(
        string? whereString = null,
        DynamicParameters? queryParams = null,
        IDbTransaction? transaction = null)
    {
        string sqlStr;
        if (string.IsNullOrWhiteSpace(whereString))
            sqlStr = $"select * from {TableName} with(nolock);";
        else
            sqlStr = $"select * from {TableName} with(nolock) where {whereString};";
        var query = await DbContext.Connection.QueryAsync<TEntity>(sqlStr, null, transaction);
        return query.ToList();
    }

    // 获取列表
    public Task<IList<TEntity>> ListAsync(
        List<string> whereCriteria,
        DynamicParameters? queryParams = null,
        IDbTransaction? transaction = null)
    {
        string? whereString = whereCriteria.Count == 0 ? null : string.Join(" and ", whereCriteria);
        return ListAsync(whereString, queryParams, transaction);
    }

    // 获取
    public Task<TEntity> GetAsync(TKey id, IDbTransaction? transaction = null)
    {
        return DbContext.Connection.GetAsync<TEntity>(id, transaction);
    }

    // 更新
    public Task<bool> UpdateAsync(TEntity entity, IDbTransaction? transaction = null)
    {
        return DbContext.Connection.UpdateAsync(entity, transaction);
    }

    // 删除
    public Task<bool> DeleteAsync(TEntity entity, IDbTransaction? transaction = null)
    {
        return DbContext.Connection.DeleteAsync(entity, transaction);
    }

    // 批量插入
    public async Task BatchInsertAsync(
        List<TEntity> entities,
        IDbTransaction? transaction = null)
    {
        if (entities.Count == 0)
            return;
        if (transaction == null)
            await DbContext.Connection.BulkInsertAsync(entities);
        else
            await transaction.BulkInsertAsync(entities);
    }

    // 批量更新
    public async Task BatchUpdateAsync(
        List<TEntity> entities,
        IDbTransaction? transaction = null)
    {
        if (entities.Count == 0)
            return;
        if (transaction == null)
            await DbContext.Connection.BulkUpdateAsync(entities);
        else
            await transaction.BulkUpdateAsync(entities);
    }

    // 获取分页列表
    public PagedDto<TEntity> PagedList(
        string? whereString = null,
        DynamicParameters? queryParams = null,
        int? pageNumber = null,
        int? pageSize = null,
        string? selectFields = null,
        string? sortFiled = null,
        bool? isAsc = null,
        IDbTransaction? transaction = null)
    {
        // 默认参数
        if (string.IsNullOrWhiteSpace(selectFields))
            selectFields = "*";
        if (string.IsNullOrWhiteSpace(sortFiled))
        {
            var entityType = typeof(TEntity);
            if (entityType is IUpdatableEntity<TKey>)
                sortFiled = "UpdatedTime";
            else if (entityType is ICreatableEntity<TKey>)
                sortFiled = "CreatedTime";
            else
                sortFiled = "Id";
        }
        if (isAsc == null)
            isAsc = false;
        // 计数
        string sqlStr;
        int totalCount;
        if (string.IsNullOrWhiteSpace(whereString))
        {
            sqlStr = $"select count(*) from {TableName} with(nolock);";
            totalCount = DbContext.Connection.ExecuteScalar<int>(sqlStr, null, transaction);
        }
        else
        {
            sqlStr = $"select count(*) from {TableName} with(nolock) where {whereString};";
            totalCount = DbContext.Connection.ExecuteScalar<int>(sqlStr, queryParams, transaction);
        }
        // 查询
        IEnumerable<TEntity> records;
        if (!pageNumber.HasValue)
            pageNumber = AneConsts.DefaultPageNumber;
        if (!pageSize.HasValue)
            pageSize = AneConsts.DefaultPageSize;
        if (string.IsNullOrWhiteSpace(whereString))
        {
            sqlStr = $@"
select {selectFields} 
from {TableName} with(nolock) 
order by {sortFiled} {(isAsc.Value ? "asc" : "desc")} 
offset ({pageNumber}-1)*{pageSize} rows fetch next {pageSize} rows only;";
            records = DbContext.Connection.Query<TEntity>(sqlStr, null, transaction);
        }
        else
        {
            sqlStr = $@"
select {selectFields} 
from {TableName} with(nolock) 
where {whereString} 
order by {sortFiled} {(isAsc.Value ? "asc" : "desc")} 
offset ({pageNumber}-1)*{pageSize} rows fetch next {pageSize} rows only;";
            records = DbContext.Connection.Query<TEntity>(sqlStr, queryParams, transaction);
        }
        // 返回结果
        return new PagedDto<TEntity>(totalCount, records, pageNumber, pageSize);
    }

    // 获取分页列表
    public PagedDto<TEntity> PagedList(
        List<string> whereCriteria,
        DynamicParameters? queryParams = null,
        int? pageNumber = null,
        int? pageSize = null,
        string? selectFields = null,
        string? sortFiled = null,
        bool? isAsc = null,
        IDbTransaction? transaction = null)
    {
        string? whereString = whereCriteria.Count == 0 ? null : string.Join(" and ", whereCriteria);
        return PagedList(whereString, queryParams, pageNumber, pageSize, selectFields, sortFiled, isAsc, transaction);
    }
}

/// <summary>
/// 仓储类
/// </summary>
public abstract class Repository<TEntity>
    : Repository<TEntity, int>, IRepository<TEntity>
    where TEntity : class, IEntity
{
}